#!/usr/bin/python3

import re
import os
import sys
import subprocess
from collections import defaultdict

file_title = '# Copyright (c) 2023 Huawei Device Co., Ltd.\n\
# Licensed under the Apache License, Version 2.0 (the "License");\n\
# you may not use this file except in compliance with the License.\n\
# You may obtain a copy of the License at\n\
#\n\
#     http://www.apache.org/licenses/LICENSE-2.0\n\
#\n\
# Unless required by applicable law or agreed to in writing, software\n\
# distributed under the License is distributed on an "AS IS" BASIS,\n\
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\
# See the License for the specific language governing permissions and\n\
# limitations under the License.\n\n'

def read_file(path, word, type_hash):
    file = open(path, 'r', encoding='UTF-8', errors='ignore')
    file2 = open("out/tmp.txt", 'w+')
    file_line = file.readlines()
    for line in file_line:
        pos = line.find("avc", 0, len(line))
        if pos < 0:
            continue
        #split = re.search(r'avc:  denied  \{ (\w+) \}.*? scontext=([\w:]+) tcontext=([\w:]+) tclass=([\w:]+)', line, re.I)
        #split = re.search(r'avc:  denied  \{ (\w+) \}.*? scontext=([\w:]+) tcontext=([\w:]+) tclass=([\w:]+)', line, re.I)
        split = re.search(r'(.*) \{(.*)\} (.*) scontext=.*:(.*):.* tcontext=.*:(.*):.* tclass=(.*) (.*)', line, re.M|re.I)
        #r'avc:  denied  \{ (\w+) \}.*? scontext=([\w:]+) tcontext=([\w:]+) tclass=([\w:]+)'
        if split:
            result = 'allow ' + split[4] + ' ' + split[5] + ':' + split[6] + ' {'  + split[2] + '};\n'
            type_hash[result] = "# " + line[pos:]
            file2.write(result)
            #print(result)
        
            if split[2] == ' ioctl ':
                split = re.search(r'(.*) \{(.*)\} (.*) ioctlcmd=(.*) scontext=.*:(.*):.* tcontext=.*:(.*):.* tclass=(.*) (.*)', line, re.M|re.I)
                result = 'allowxperm ' + split[5] + ' ' + split[6] + ':' + split[7]  + split[2] + split[4] + ';\n'
                #print(result)
                type_hash[result] = "# " + line[pos:]
                file2.write(result)


def trans_avc(path, type_hash):
    outpath = os.path.join('out', 'te')
    if os.path.exists(outpath):
        print("outpath exsits ! policy write append")
    else:
        os.makedirs(outpath)
    key_word = []
    read_file(path, key_word, type_hash)
    rc=os.system('cat out/tmp.txt | sort | uniq > out/tmp2.txt')
    if rc:
        raise Exception(rc)
    file = open('out/tmp2.txt', 'r')
    file_line = file.readlines()
    subj = ''
    last = ''
    for line in file_line:
        split = re.search(r'allow (.*) (.*):(.*) \{(.*)\};', line, re.M | re.I)
        if split:
            subj = split[1]
            if split[4] == ' associate ':
                filesys = open('out/te/filesystem.te', 'a+', newline='\n')
                filesys.write(line) 
                continue
            if subj != last:
                last = subj
                file_name = 'out/te/'  + last + '.te'
                te_file = open(file_name, 'a+', newline='\n')
            te_file.write(line)
        else:
            split = re.search(r'allowxperm (.*) (.*):(.*) (.*);', line, re.M | re.I)
            if split:
                file_name = 'out/te/' + split[1]  + '.te'
                te_file = open(file_name, 'a+', newline='\n')
                te_file.write(line)

def format(type_hash):
    os.mkdir('format_out')
    files = os.listdir('sort_out')

    for file_name in files:
        file_read = open('sort_out/' + file_name, 'r')
        file_write = open('format_out/' + file_name, 'w+')
        file_write.write(file_title)
        la = ''
        ls = ''
        lo = ''
        lc = ''
        a = ''
        s = ''
        o = ''
        c = ''
        oper = []
        log = ''

        lines = file_read.readlines()
        for line in lines:
            split = re.search(r'(allow|allowxperm)\s+(\S+)\s+(\S+):(\S+)\s+(ioctl\s+)?(\{)?([A-Za-z0-9 _]*)(\})?;', line, re.M|re.I)
            if split == None:
                print("following line skiped:")
                print(line)
                continue
            
            a = split[1] 
            s = split[2] 
            o = split[3] 
            c = split[4] 
            if la == '':
                la = a
                ls = s
                lo = o
                lc = c 
                oper.append(split[7])
                log += type_hash[line]
            elif ( a == la and s == ls and o == lo and c == lc ):
                oper.append(split[7])
                log += type_hash[line]
            else:
                if ( la == 'allow'):
                    cmd = 'allow ' + ls + ' ' + lo + ':' + lc + ' { '
                    for i in oper:
                        cmd += i.strip() + ' '
                    cmd += '};\n'
                    file_write.write(log);
                    file_write.write(cmd);
                    file_write.write('\n');
                else:
                    cmd = 'allowxperm ' + ls + ' ' + lo + ':' + lc + ' ioctl { '
                    for i in oper:
                        cmd += i + ' '
                    cmd += '};\n'
                    file_write.write(log);
                    file_write.write(cmd);
                    file_write.write('\n');
                
                la = a
                ls = s
                lo = o
                lc = c
                log = ''
                oper = []
                log += type_hash[line]
                oper.append(split[7])

        if ( la == 'allow'):
            cmd = 'allow ' + ls + ' ' + lo + ':' + lc + ' { '
            for i in oper:
                cmd += i.strip() + ' '
            cmd += '};\n'
            file_write.write(log);
            file_write.write(cmd);
        else:
            cmd = 'allowxperm ' + ls + ' ' + lo + ':' + lc + ' ioctl { '
            for i in oper:
                cmd += i + ' '
            cmd += '};\n'
            file_write.write(log);
            file_write.write(cmd);
        file_read.close()
        file_write.close()
        cmd = 'dos2unix ' + 'format_out/' + file_name
        subprocess.run(cmd, shell=False)

def sort_and_uniq():
    te_path = os.path.join('out', 'te')
    if not os.path.exists(te_path):
        print("path out/te not exist")
        raise Exception(1)
    out = 'sort_out'
    if os.path.exists(out):
        print('exists')
    else:
        os.mkdir(out)
    files = os.listdir(te_path);
    for item in files:
        cmd = 'cat out/te/' + item + ' | sort | uniq > ' + out + '/' + item
        os.system(cmd)


if __name__ == '__main__':
    if len(sys.argv) >= 2:
        path = sys.argv[1]
    else:
        print("usage:" + sys.argv[0] + " logfile")
        exit(1)

    type_hash = defaultdict(str)
    for parent, dirnames, filenames in os.walk(path):
        for filename in filenames:
            print(filename)
            trans_avc(os.path.join(parent, filename), type_hash)
    sort_and_uniq()
    format(type_hash)
    exit(0)